package pikes.html;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.custommonkey.xmlunit.XMLUnit;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import pikes.html.xhtml.XHTMLPage;
import pikes.html.xhtml.version10.HtmlPage;
import pikes.html.xhtml.version10.StrictDocType;
import pikes.html.xhtml.version11.XHtml11DocType;
import pikes.mock.XMLRenderingTest;
import pikes.xml.XMLTag;

public class RenderingTestCase {

	private static Map<String,Resource> publicIDFileNamesMap = new HashMap<String, Resource>();
	static {
		publicIDFileNamesMap.put("-//W3C//DTD XHTML 1.0 Transitional//EN",new ClassPathResource("xhtml1-transitional.dtd"));
		publicIDFileNamesMap.put("-//W3C//ENTITIES Latin 1 for XHTML//EN",new ClassPathResource("xhtml-lat1.ent"));
		publicIDFileNamesMap.put("-//W3C//ENTITIES Symbols for XHTML//EN",new ClassPathResource("xhtml-symbol.ent"));
		publicIDFileNamesMap.put("-//W3C//ENTITIES Special for XHTML//EN",new ClassPathResource("xhtml-special.ent"));
		publicIDFileNamesMap.put("-//W3C//DTD XHTML 1.0 Strict//EN",new ClassPathResource("xhtml1-strict.dtd"));
		publicIDFileNamesMap.put("-//W3C//DTD XHTML 1.1//EN",new ClassPathResource("xhtml11-flat.dtd"));
	}
	
	@BeforeClass
	public static void configureXMLUnit() throws Exception {
		XMLUnit.getTestDocumentBuilderFactory().setValidating(false);
		XMLUnit.getControlDocumentBuilderFactory().setValidating(false);
		XMLUnit.getSAXParserFactory().setValidating(false);

		EntityResolver entityResolver = new ClasspathDTDCatalog(publicIDFileNamesMap);
		
		XMLUnit.setTestEntityResolver(entityResolver);
		XMLUnit.setControlEntityResolver(entityResolver);
	}
	
	@Test
	public void emptyHtmlPage() throws Exception {
		HtmlPage page = new HtmlPage();
		XMLRenderingTest.assertRendering(page,"<?xml version=\"1.0\"?><!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"/>");
	}
	
	@Test
	public void emptyHtmlPageWithUTF8Encoding() throws Exception {
		HtmlPage page = new HtmlPage();
		page.setEncoding("UTF-8");
		XMLRenderingTest.assertRendering(page,"<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"/>");
	}
	
	@Test
	public void htmlPageWithLanguageAttributes() throws Exception {
		HtmlPage page = new HtmlPage() {

			@Override
			protected void buildHtmlPage(XMLTag htmlTag, Map model, HttpServletRequest request) {
				htmlTag.addAttribute("xml:lang", "en");
				htmlTag.addAttribute("lang", "en");
			}

		};
		XMLRenderingTest.assertRendering(page,"<?xml version=\"1.0\"?><!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\"/>");
	}
	
	@Test
	public void htmlPageWithHeadTag() throws Exception {
		HtmlPage page = new HtmlPage() {

			@Override
			protected void buildHtmlPage(XMLTag htmlTag, Map model, HttpServletRequest request) {
				htmlTag.addTag(new XMLTag("head"));
			}

		};
		XMLRenderingTest.assertRendering(page,"<?xml version=\"1.0\"?><!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"><head/></html>");
	}
	
	@Test
	public void strictXHtmlPage() throws Exception {
		XHTMLPage xhtmlPage = new XHTMLPage();
		xhtmlPage.setDocType(new StrictDocType());
		XMLRenderingTest.assertRendering(xhtmlPage,"<?xml version=\"1.0\"?><!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title></title></head><body/></html>");
	}
	
	@Test
	public void xhtml11Page() throws Exception {
		HtmlPage page = new HtmlPage();
		page.setDocType(new XHtml11DocType());
		XMLRenderingTest.assertRendering(page,"<?xml version=\"1.0\"?><!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"/>");
	}
}

class ClasspathDTDCatalog implements EntityResolver {
	
	private Map<String,Resource> resourcesMap = new HashMap<String, Resource>();
	
	public ClasspathDTDCatalog(Map<String,Resource> resourcesMap) {
		this.resourcesMap = resourcesMap;
	}
	
	public InputSource resolveEntity(String publicId, String systemId)
		throws SAXException, IOException {
		
		if (!resourcesMap.containsKey(publicId)) {
			return new InputSource(new UrlResource(systemId).getInputStream());
		}
		
		return new InputSource(resourcesMap.get(publicId).getInputStream());
	}
}